#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define DEV_NAME            "led_chrdev"
#define DEV_CNT                 (1)
//GPIO0_C7
#define GPIO0_BASE (0xfdd60000)  //GPIO0的基地址

//一个寄存器32位，其中高16位都是写使能位，控制低16位的写使能；低16位对应16个引脚，控制引脚的输出电平
#define GPIO0_DR_L (GPIO0_BASE + 0x0000)  // GPIO0的低十六位引脚的数据寄存器地址
#define GPIO0_DR_H (GPIO0_BASE + 0x0004)  // GPIO0的高十六位引脚的数据寄存器地址

//一个寄存器32位，其中高16位都是写使能位，控制低16位的写使能；低16位对应16个引脚，控制引脚的输入输出模式
#define GPIO0_DDR_L (GPIO0_BASE + 0x0008)   // GPIO0的低十六位引脚的数据方向寄存器地址
#define GPIO0_DDR_H (GPIO0_BASE + 0x000C)   // GPIO0的高十六位引脚的数据方向寄存器地址

static dev_t devno;
struct class *led_chrdev_class;

struct led_chrdev {
    struct cdev dev;
    unsigned int __iomem *va_dr;
    unsigned int __iomem *va_ddr;

    unsigned int led_pin; // 引脚
};

static int led_chrdev_open(struct inode *inode, struct file *filp)
{
    unsigned int val = 0;
    struct led_chrdev *led_cdev = (struct led_chrdev *)container_of(inode->i_cdev, struct led_chrdev, dev);
    filp->private_data = container_of(inode->i_cdev, struct led_chrdev, dev);

    printk("open\n");

    // 设置输出模式
    val = ioread32(led_cdev->va_ddr);
    val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));
    val |= ((unsigned int)0X1 << (led_cdev->led_pin));
    iowrite32(val,led_cdev->va_ddr);

    //输出高电平
    val = ioread32(led_cdev->va_dr);
    val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));
    val |= ((unsigned int)0x1 << (led_cdev->led_pin));
    iowrite32(val, led_cdev->va_dr);

    return 0;
}

static int led_chrdev_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static ssize_t led_chrdev_write(struct file *filp, const char __user * buf,
                size_t count, loff_t * ppos)
{
    unsigned long val = 0;
    char ret = 0;
    struct led_chrdev *led_cdev = (struct led_chrdev *)filp->private_data;

    get_user(ret, buf);
    val = ioread32(led_cdev->va_dr);
    if (ret == '0'){
            val |= ((unsigned int)0x01 << (led_cdev->led_pin+16));
            val &= ~((unsigned int)0x01 << (led_cdev->led_pin));   /*设置GPIO引脚输出低电平*/
    }
    else{
            val |= ((unsigned int)0x01 << (led_cdev->led_pin+16));
            val |= ((unsigned int)0x01 << (led_cdev->led_pin));    /*设置GPIO引脚输出高电平*/
    }
    iowrite32(val, led_cdev->va_dr);

    return count;
}

static struct file_operations led_chrdev_fops = {
    .owner = THIS_MODULE,
    .open = led_chrdev_open,
    .release = led_chrdev_release,
    .write = led_chrdev_write,
};

static struct led_chrdev led_cdev[DEV_CNT] = {
    {.led_pin = 7},         // 偏移，GPIO0_C7偏移7位
};

static __init int led_chrdev_init(void)
{
    int i = 0;
            dev_t cur_dev;
            unsigned int val = 0;

    printk("led_chrdev init (lubancat2  GPIO0_C7)\n");

    led_cdev[0].va_dr   = ioremap(GPIO0_DR_H, 4);    // 映射数据寄存器物理地址到虚拟地址，GPIO0_C7需要设置GPIO0_DR_H
    led_cdev[0].va_ddr  = ioremap(GPIO0_DDR_H, 4);   // 映射数据方向寄存器物理地址到虚拟地址，GPIO0_C7需要设置GPIO0_DDR_H

            alloc_chrdev_region(&devno, 0, DEV_CNT, DEV_NAME);

            led_chrdev_class = class_create(THIS_MODULE, "led_chrdev");

            for (; i < DEV_CNT; i++) {
                    cdev_init(&led_cdev[i].dev, &led_chrdev_fops);
                    led_cdev[i].dev.owner = THIS_MODULE;

                    cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);

                    cdev_add(&led_cdev[i].dev, cur_dev, 1);

                    device_create(led_chrdev_class, NULL, cur_dev, NULL,
                                            DEV_NAME "%d", i);
            }

            return 0;
}

module_init(led_chrdev_init);

static __exit void led_chrdev_exit(void)
{
    int i;
    dev_t cur_dev;
    printk("led chrdev exit (lubancat2  GPIO0_C7)\n");

    for (i = 0; i < DEV_CNT; i++) {
        iounmap(led_cdev[i].va_dr);                 // 释放数据寄存器虚拟地址
        iounmap(led_cdev[i].va_ddr);        // 释放数据方向寄存器虚拟地址
    }

    for (i = 0; i < DEV_CNT; i++) {
        cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);

        device_destroy(led_chrdev_class, cur_dev);

        cdev_del(&led_cdev[i].dev);

    }
    unregister_chrdev_region(devno, DEV_CNT);
    class_destroy(led_chrdev_class);

}

module_exit(led_chrdev_exit);

MODULE_AUTHOR("Embedfire");
MODULE_LICENSE("GPL");

修改为 GPIO4_B5

#define GPIO4_BASE (0xFEC50000)  //GPIO4的基地址

//一个寄存器32位，其中高16位都是写使能位，控制低16位的写使能；低16位对应16个引脚，控制引脚的输出电平
#define GPIO4_DR_L (GPIO4_BASE + 0x0000)  // GPIO4的低十六位引脚的数据寄存器地址
#define GPIO4_DR_H (GPIO4_BASE + 0x0004)  // GPIO4的高十六位引脚的数据寄存器地址

//一个寄存器32位，其中高16位都是写使能位，控制低16位的写使能；低16位对应16个引脚，控制引脚的输入输出模式
#define GPIO4_DDR_L (GPIO4_BASE + 0x0008)   // GPIO4的低十六位引脚的数据方向寄存器地址
#define GPIO4_DDR_H (GPIO4_BASE + 0x000C)   // GPIO4的高十六位引脚的数据方向寄存器地址

......

static struct led_chrdev led_cdev[DEV_CNT] = {
    {.led_pin = 13},        // 偏移，GPIO4_B5偏移8+5位，即偏移13位
};

......

led_cdev[0].va_dr   = ioremap(GPIO4_DR_L, 4);        // 映射数据寄存器物理地址到虚拟地址，GPIO4_B5位于低32号引脚，需要设置GPIO4_DR_L
led_cdev[0].va_ddr  = ioremap(GPIO4_DDR_L, 4);       // 映射数据方向寄存器物理地址到虚拟地址，GPIO4_B5位于低32号引脚，需要设置GPIO4_DDR_L
